/*****************************************************************************
*
* File: spi_sseg.c
*
* Description: Contains functions to initialize SSEG display.
*
* Author: Kevin Casteel, Luis Castillo
*
* Revisions: v-1.0 (4/20/11)
*            v-1.1 (4/22/11)
*
******************************************************************************/

#include "spi_sseg.h"
#include <avr/io.h>


//--------------------------------------------------------------
//- Function: SPI_MasterInit()
//- 
//- return value: none
//- parameters: none
//-
//- Description: Initializes the AVR device as a master and 
//- and turns on the device and sets the clock frequency. 
//- For convenience, this function also configures the SPI
//- port GPIOs
//---------------------------------------------------------------
void SPI_MasterInit(void)
{
	/* Set MOSI and SCK output, all others input */
	DDRB = (1<<SPI_MOSI)|(1<<SPI_SCK)|(1<<SPI_SS);
	/* Enable SPI, Master, set clock rate fck/16 */
	SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
}



//--------------------------------------------------------------
//- Function: SPI_MasterTransmit()
//- 
//- return value: none
//- parameters: data to be transmitted
//-
//- Description: This function selects the device, transmits
//- the data, waits for a the transmission to complete with 
//- a poll, then deselects the device. 
//---------------------------------------------------------------
void SPI_MasterTransmit(uint8_t data)
{
	/* Start transmission */
	SPDR = data;
	/* Wait for transmission complete */
	while(!(SPSR & (1<<SPIF)))
		;
}



//--------------------------------------------------------------
//- Function: SSEG_Set_Brightness()
//- 
//- return value: none
//- parameters: val, the value to set the brightness of display
//-
//- Description: This function set the brightness of the 
//- display where 255 is off and 0 is on as bright as possible. 
//---------------------------------------------------------------
void SSEG_Set_Brightness(uint8_t val)
{   
	PORTB = (0<<SPI_SS); //- clear SS
    //- transmit brightness command
	SPI_MasterTransmit(SSEG_BRIGHTNESS);
	//- transmit brightness value (0x00 highest brightness)
	SPI_MasterTransmit(val);
	PORTB = (1<<SPI_SS); //- set SS
}


//--------------------------------------------------------------
//- Function: SSEG_Reset()
//- 
//- return value: none
//- parameters: none
//-
//- Description: This function turns off all display elements. 
//---------------------------------------------------------------
void SSEG_Reset(void)
{
	PORTB = (0<<SPI_SS); //- clear SS
	//- transmit reset command
	SPI_MasterTransmit(SSEG_RESET);
	PORTB = (1<<SPI_SS); //- set SS
}



//--------------------------------------------------------------
//- Function: SSEG_Write_4vals_array()
//- 
//- return value: none
//- parameters: pointer to an array
//-
//- Description: This function takes an pointer that in theory is 
//- pointing to an array of four byte values, one for 
//- each of the 7-segment display locations. The four values
//- are then written to the 7-segment display.  
//---------------------------------------------------------------
void SSEG_Write_4vals_array(uint8_t* vals)
{
	PORTB = (0<<SPI_SS); //- clear SS
	//- transmit values 0-3
	SPI_MasterTransmit(*vals++);
	SPI_MasterTransmit(*vals++);
	SPI_MasterTransmit(*vals++);
	SPI_MasterTransmit(*vals);
	PORTB = (1<<SPI_SS); //- set SS
}



//--------------------------------------------------------------
//- Function: SSEG_Write_digit()
//- 
//- return value: none
//- parameters: digit location and digit value
//-
//- Description: This is a wrapper function for writing 
//- individual digits to the display. In this case, you need 
//- to first send the initial escape character before you 
//- send the actual data. 
//---------------------------------------------------------------
void SSEG_Write_digit(uint8_t digit, uint8_t val)
{
	PORTB = (0<<SPI_SS); //- clear SS
	//- transmit command to specify which digit to write to
	switch(digit)
	{
		case DIGIT_1:
			SPI_MasterTransmit(SSEG_DIG1);
			break;
		case DIGIT_2:
			SPI_MasterTransmit(SSEG_DIG2);
			break;
		case DIGIT_3:
			SPI_MasterTransmit(SSEG_DIG3);
			break;
		case DIGIT_4:
			SPI_MasterTransmit(SSEG_DIG4);
			break;
		default:
			break;
	}
	//- transmit data to specified digit
	switch(val)
	{
		case ZERO:
			SPI_MasterTransmit(SSEG_0);
			break;
		case ONE:
			SPI_MasterTransmit(SSEG_1);
			break;
		case TWO:
			SPI_MasterTransmit(SSEG_2);
			break;
		case THREE:
			SPI_MasterTransmit(SSEG_3);
			break;
		case FOUR:
			SPI_MasterTransmit(SSEG_4);
			break;
		case FIVE:
			SPI_MasterTransmit(SSEG_5);
			break;
		case SIX:
			SPI_MasterTransmit(SSEG_6);
			break;
		case SEVEN:
			SPI_MasterTransmit(SSEG_7);
			break;
		case EIGHT:
			SPI_MasterTransmit(SSEG_8);
			break;
		case NINE:
			SPI_MasterTransmit(SSEG_9);
			break;
		case ALPHA:
			SPI_MasterTransmit(SSEG_A);
			break;
		case BETA:
			SPI_MasterTransmit(SSEG_B);
			break;
		case CHARLIE:
			SPI_MasterTransmit(SSEG_C);
			break;
		case DELTA:
			SPI_MasterTransmit(SSEG_D);
			break;
		case ECHO:
			SPI_MasterTransmit(SSEG_E);
			break;
		case FOXTROT:
			SPI_MasterTransmit(SSEG_F);
			break;
		case BLANK:
			SPI_MasterTransmit(SSEG_BLANK);
			break;
		default:
			break;
	}
	PORTB = (1<<SPI_SS); //- set SS
}



//--------------------------------------------------------------
//- Function: SSEG_Write_left_digits()
//- 
//- return value: none
//- parameters: binary value for display on two left-most digits
//-
//- Description: This function decomposes the sent value into
//- a tens and ones digit the then sends them off to the two 
//- left-most digits of the display. This function also handles
//- lead zero blanking. 
//---------------------------------------------------------------
void SSEG_Write_left_digits(uint8_t val)
{
	uint8_t tens;
	uint8_t ones;

	//- calculate tens digit
	if((tens = val / 10) == 0)
	{
		tens = BLANK;
	}
	//- calculate ones digit
	ones = val % 10;

	//- call function to write tens
	//- and ones to left-most digits
	SSEG_Write_digit(DIGIT_1, tens);
	SSEG_Write_digit(DIGIT_2, ones);
}



//--------------------------------------------------------------
//- Function: SSEG_Write_right_digits()
//- 
//- return value: none
//- parameters: binary value for display on two right-most digits
//-
//- Description: This function decomposes the sent value into
//- a tens and ones digit the then sends them off to the two 
//- right-most digits of the display. This function also handles
//- lead zero blanking. 
//---------------------------------------------------------------
void SSEG_Write_right_digits(uint8_t val)
{
	uint8_t tens;
	uint8_t ones;

	//- calculate tens digit
	if((tens = val / 10) == 0)
	{
		tens = BLANK;
	}
	//- calculate ones digit
	ones = val % 10;

    //- call function to write tens
	//- and ones to right-most digits
	SSEG_Write_digit(DIGIT_3, tens);
	SSEG_Write_digit(DIGIT_4, ones);
}


//--------------------------------------------------------------
//- Function: SSEG_Write_Decimal_Point()
//- 
//- return value: none
//- parameters: the individual values for the various "dots" on 
//-             the 7-segment display. 
//-
//- Description: Writes decimal point values to the display. 
//- There are six different values that can be written. Check 
//- out the 7-segment device spec for details on decimal points.
//---------------------------------------------------------------
void SSEG_Write_Decimal_Point(uint8_t val)
{
	PORTB = (0<<SPI_SS); //- clear SS
	
	//- transmit decimal point control command
	SPI_MasterTransmit(SSEG_DEC_PNT);
	//- transmit value to set/clear decimal points/colon
	switch(val)
	{
		case ZERO:
			SPI_MasterTransmit(SSEG_DP_0);
			break;
		case ONE:
			SPI_MasterTransmit(SSEG_DP_1);
			break;
		case TWO:
			SPI_MasterTransmit(SSEG_DP_2);
			break;
		case THREE:
			SPI_MasterTransmit(SSEG_DP_3);
			break;
		case FOUR:
			SPI_MasterTransmit(SSEG_DP_4);
			break;
		case FIVE:
			SPI_MasterTransmit(SSEG_DP_5);
			break;
		case BLANK:
			SPI_MasterTransmit(SSEG_BLANK);
			break;
		default:
			break;
	}
	PORTB = (1<<SPI_SS); //- set SS
}


